package com.qiudao.basestudy.util;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Description: 列表去重工具类
 * 依赖 org.apache.commons.lang3
 * @author: gdc
 * @date: 2019/9/1
 * @version 1.0
 */
public class ListFilterUtils {

    /**
     * list去重
     *
     * @param list
     * @param keyExtractor
     * @param <T>
     * @return
     */
    public static <T> List<T> filterByDistinctKey(List<T> list,
                                                  Function<? super T, Object> keyExtractor) {
        if (CollectionUtils.isEmpty(list)) {
            return list;
        }
        return list.stream().filter(distinctByKey(keyExtractor)).collect(Collectors.toList());
    }

    /**
     * list去重, 去除左边列表不在右边列表里的元素
     *
     * @param leftList     需要过滤的list
     * @param rightList    已经存在的元素list
     * @param keyExtractor
     * @param <T>
     * @return
     */
    public static <T> List<T> filterByList(List<T> leftList, List<T> rightList,
                                           Function<? super T, Object> keyExtractor) {
        if (CollectionUtils.isEmpty(leftList)) {
            return leftList;
        }

        Set<Object> set = rightList.stream().map(t -> keyExtractor.apply(t))
                .collect(Collectors.toSet());

        return filterByDistinctKey(leftList, keyExtractor).stream()
                .filter(t -> !set.contains(keyExtractor.apply(t))).collect(Collectors.toList());
    }

    /**
     * 过滤掉list中的空字符串和null
     *
     * @param list
     * @return
     */
    public static List<String> filterWhiteStr(List<String> list) {
        if (CollectionUtils.isEmpty(list)) {
            return list;
        }

        return list.stream().filter(StringUtils::isNotEmpty).distinct()
                .collect(Collectors.toList());
    }

    private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>(16);
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;

    }
}
